package com.bajiao.service.order.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.alibaba.fastjson.JSONObject;
import com.bajiao.common.constant._Whole;
import com.bajiao.common.exception.DataHandleException;
import com.bajiao.common.util.*;
import com.bajiao.common.util.encryption.AesEncryptUtil;
import com.bajiao.entity.account.Account;
import com.bajiao.entity.coupon.Coupon;
import com.bajiao.entity.order.CouponOrder;
import com.bajiao.entity.order.Order;
import com.bajiao.entity.order.RefundCouponOrder;
import com.bajiao.entity.order.RefundOrder;
import com.bajiao.entity.recharge.RechargeMenu;
import com.bajiao.entity.user.UserCoupon;
import com.bajiao.mapper.order.CouponOrderMapper;
import com.bajiao.service.coupon.CouponService;
import com.bajiao.service.order.CouponOrderService;
import com.bajiao.service.order.RefundCouponOrderService;
import com.bajiao.service.recharge.RechargeMenuService;
import com.bajiao.service.store.StoreService;
import com.bajiao.service.user.UserCouponService;
import com.bajiao.service.user.UserService;
import com.bajiao.vo.order.*;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @Description: 优惠券订单
 * @Author: FanJq
 * @Date:   2024-12-14
 * @Version: V1.0
 */
@Service
public class CouponOrderServiceImpl extends ServiceImpl<CouponOrderMapper, CouponOrder> implements CouponOrderService {

    @Resource
    private CouponService couponService;
    @Resource
    private UserCouponService userCouponService;
    @Resource
    private UserService userService;
    @Resource
    private RefundCouponOrderService refundCouponOrderService;
    @Resource
    private StoreService storeService;
    @Resource
    private RechargeMenuService rechargeMenuService;
    @Resource
    private RedisUtil redisUtil;

    /**
     * @Description
     * 根据订单编号获取
     * @date 2024/12/16 10:22
     * @author FanJq
     * @param userId
     * @param orderNo
     * @return {@link CouponOrder}
    */
    @Override
    public CouponOrder getByOrderNo(String userId, String orderNo) {
        CouponOrder couponOrder = super.lambdaQuery()
                .eq(CouponOrder::getUserId, userId)
                .eq(CouponOrder::getOrderNo, orderNo)
                .one();
        return couponOrder;
    }

    /**
     * @Description
     * 确认订单
     * @date 2024/12/18 16:01
     * @author FanJq
     * @param userId
     * @param couponId
     * @return {@link CouponOrder}
    */
    @Override
    public CouponOrder confirm(String userId, String couponId) {
        Coupon coupon = couponService.getById(couponId);
        if (ObjectUtil.isNull(coupon) || coupon.getStatus() != _Whole.ONE)
            throw new DataHandleException("优惠券不存在");
        if (new Date().getTime() > coupon.getEndTime().getTime())
            throw new DataHandleException("优惠券已不可购买");
        UserCoupon usableCoupon = userCouponService.getUserUsableCoupon(userId, couponId);
        if (ObjectUtil.isNotNull(usableCoupon))
            throw new DataHandleException("您已拥有该优惠券");
        CouponOrder order = this.calculateOrder(userId, coupon);
        if (coupon.getScope().intValue() == _Whole.TWO) {
            String storeTitle = storeService.getStoreTitle(coupon.getStoreId());
            order.setStoreTitle(storeTitle);
        }
        return order;
    }

    /**
     * @Description
     * 创建订单
     * @date 2024/12/14 16:43
     * @author FanJq
     * @param userId
     * @param couponId
     * @return {@link Order}
     */
    @Override
    public CouponOrder create(String userId, String couponId, String remark) {
        CouponOrder order = this.confirm(userId, couponId);
        order.setRemark(remark);
        order.setExpireTime(DateUtil.addMinute(new Date(), 30));
        super.save(order);
        redisUtil.set(_Whole.couponExpiredKey + order.getId(), order.getId(), 60 * 30);
        return order;
    }

    /**
     * @Description
     * 订单支付
     * @date 2024/12/18 16:17
     * @author FanJq
     * @param userId
     * @param couponId
     * @param remark
     * @return {@link String}
    */
    @Override
    //@Transactional(rollbackFor = Exception.class)
    public String toPay(String userId, String couponId, String remark) {
        //@create by FanJq 2024/12/18 16:18 创建订单
        CouponOrder order = this.create(userId, couponId, remark);
        BigDecimal payPrice = order.getPayPrice();
        if (payPrice.signum() > _Whole.ZERO) {
            Account account = userService.getAccount(userId);
            if (payPrice.compareTo(account.getMoney()) > _Whole.ZERO) {
                BigDecimal lackAmount = payPrice.subtract(account.getMoney());
                RechargeMenu rechargeMenu = rechargeMenuService.lambdaQuery()
                        .ge(RechargeMenu::getAmount, lackAmount)
                        .orderByAsc(RechargeMenu::getAmount)
                        .last("LIMIT 1").one();
                if (ObjectUtil.isNull(rechargeMenu)) {
                    rechargeMenu = rechargeMenuService.lambdaQuery()
                            .orderByDesc(RechargeMenu::getAmount)
                            .last("LIMIT 1").one();
                }
                throw new DataHandleException(String.format("下单金额美豆不足，请前往充值美豆充%s送%s",
                        rechargeMenu.getAmount().stripTrailingZeros().toPlainString(),
                        rechargeMenu.getGiveAmount().stripTrailingZeros().toPlainString()
                ), 5);
            }
            userService.changeMoney(userId, payPrice, _Whole.TWO, order.getOrderNo(), "购买优惠券", _Whole.TWO);
        }
        //@create by FanJq 2024/12/18 16:21 支付完成事件
        this.complete(order);
        return order.getOrderNo();
    }

    @Override
    public List<String> toNewPay(String userId, String couponIds, String remark) {
        String[] array = couponIds.split(",");
        List<String> list = new ArrayList<>();
        for (String couponId : array) {
            Coupon coupon = couponService.getById(couponId);
            if(coupon.getCount() <= 0){
                throw new DataHandleException("该店铺"+coupon.getMeet()+"元优惠劵数量已用完");
            }

            //@create by FanJq 2024/12/18 16:18 创建订单
            CouponOrder order = this.create(userId, couponId, remark);
            BigDecimal payPrice = order.getPayPrice();
            if (payPrice.signum() > _Whole.ZERO) {
                Account account = userService.getAccount(userId);
                if (payPrice.compareTo(account.getMoney()) > _Whole.ZERO) {
                    BigDecimal lackAmount = payPrice.subtract(account.getMoney());
                    RechargeMenu rechargeMenu = rechargeMenuService.lambdaQuery()
                            .ge(RechargeMenu::getAmount, lackAmount)
                            .orderByAsc(RechargeMenu::getAmount)
                            .last("LIMIT 1").one();
                    if (ObjectUtil.isNull(rechargeMenu)) {
                        rechargeMenu = rechargeMenuService.lambdaQuery()
                                .orderByDesc(RechargeMenu::getAmount)
                                .last("LIMIT 1").one();
                    }
                    throw new DataHandleException(String.format("下单金额美豆不足，请前往充值美豆充%s送%s",
                            rechargeMenu.getAmount().stripTrailingZeros().toPlainString(),
                            rechargeMenu.getGiveAmount().stripTrailingZeros().toPlainString()
                    ), 5);
                }
                userService.changeMoney(userId, payPrice, _Whole.TWO, order.getOrderNo(), "购买优惠券", _Whole.TWO);
            }
            //@create by FanJq 2024/12/18 16:21 支付完成事件
            this.complete(order);
            list.add(order.getOrderNo());
        }
        return list;
    }

    /**
     * @Description
     * 支付完成
     * @date 2024/12/18 17:02
     * @author FanJq
     * @param order
     * @return
    */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void complete(CouponOrder order) {
        order.setPayType(_Whole.ONE);
        order.setPayTime(new Date());
        order.setStatus(_Whole.ONE);
        super.updateById(order);
        Coupon coupon = couponService.getById(order.getCouponId());
        //@create by FanJq 2024/12/18 16:43 创建用户优惠券
        userCouponService.create(order.getUserId(), coupon, order.getOrderNo());
        //@create by FanJq 2024/12/18 16:44 处理销量
        couponService.salesLogic(order.getCouponId(), _Whole.ONE);
        // 处理优惠劵剩余数量
        coupon.setCount(coupon.getCount() - 1);
        couponService.updateById(coupon);
    }

    /**
     * @Description
     * 订单分页列表
     * @date 2024/12/18 17:24
     * @author FanJq
     * @param userId
     * @param status
     * @return {@link List< CouponOrderResponse>}
    */
    @Override
    public List<CouponOrderResponse> getOrderPage(String userId, Integer status) {
        if (status.intValue() > _Whole.NINE)
            status = null;
        List<CouponOrderResponse> responseList = super.baseMapper.getOrderPage(userId, status);
        responseList.forEach(model -> {
            model.setQuota(model.getQuotaBD().stripTrailingZeros().toPlainString());
            if (model.getType() == _Whole.ONE) {
                model.setQuota(model.getQuotaBD().multiply(new BigDecimal("10")).stripTrailingZeros().toPlainString());
            }
            if (model.getStatus().intValue() == _Whole.ONE) {
                UserCoupon userCoupon = userCouponService.getByOrderNo(userId, model.getOrderNo());
                if (ObjectUtil.isNotNull(userCoupon)) {
                    model.setReceiveTime(DateUtils.time_sdf.get().format(userCoupon.getReceiveTime()));
                    model.setExpireTime(DateUtils.time_sdf.get().format(userCoupon.getExpireTime()));
                }
            }
            if (model.getStatus().intValue() == _Whole.ZERO && ObjectUtil.isNotNull(model.getOrderExpireTime())) {
                model.setOrderExpireTimeStamp(model.getOrderExpireTime().getTime() / 1000);
            }
        });
        return responseList;
    }

    /**
     * @Description
     * 同步订单状态
     * @date 2024/12/19 10:38
     * @author FanJq
     * @param userCoupon
     * @return
    */
    @Override
    public void syncStatus(UserCoupon userCoupon) {
        CouponOrder couponOrder = this.getByOrderNo(userCoupon.getUserId(), userCoupon.getOrderNo());
        if (ObjectUtil.isNull(couponOrder)) return;
        switch (userCoupon.getStatus()) {
            case _Whole.ZERO: //@create by FanJq 2024/12/19 10:39 失效
                couponOrder.setStatus(_Whole.FOUR);
                break;
            case _Whole.ONE: //@create by FanJq 2024/12/19 10:39 可用
                couponOrder.setStatus(_Whole.ONE);
                break;
            case _Whole.TWO: //@create by FanJq 2024/12/19 10:40 已使用
                couponOrder.setStatus(_Whole.TWO);
                break;
            case _Whole.THREE: //@create by FanJq 2024/12/19 10:40 已核销
                couponOrder.setStatus(_Whole.THREE);
                couponOrder.setVerifyTime(userCoupon.getVerifyTime());
                break;
        }
        super.updateById(couponOrder);
    }

    /**
     * @Description
     * 取消订单
     * @date 2024/12/19 11:18
     * @author FanJq
     * @param userId
     * @param orderNo
     * @return
    */
    @Override
    public void cancel(String userId, String orderNo) {
        CouponOrder order = this.getByOrderNo(userId, orderNo);
        if (ObjectUtil.isNull(order))
            throw new DataHandleException("订单不存在");
        if (order.getStatus() != _Whole.ZERO)
            throw new DataHandleException("当前订单不支持取消");
        //@create by FanJq 2024/12/16 17:51 更新订单状态
        super.lambdaUpdate()
                .set(CouponOrder::getStatus, _Whole.NINE)
                .eq(CouponOrder::getOrderNo, orderNo)
                .eq(CouponOrder::getUserId, userId)
                .update();
    }

    /**
     * @Description
     * 申请退款
     * @date 2024/12/20 14:20
     * @author FanJq
     * @param userId
     * @param orderNo
     * @param reason
     * @return {@link String}
    */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String askRefund(String userId, String orderNo, String reason) {
        CouponOrder order = this.getByOrderNo(userId, orderNo);
        if (ObjectUtil.isNull(order))
            throw new DataHandleException("订单不存在");
        if (order.getStatus() != _Whole.ONE)
            throw new DataHandleException("当前订单不支持退款");
        //@create by FanJq 2024/12/20 14:52 创建退款单
        Boolean b = refundCouponOrderService.create(order, reason);
        if (b) {
            //@create by FanJq 2024/12/19 14:32 更新订单状态
            super.lambdaUpdate()
                    .set(CouponOrder::getStatus, _Whole.SEVEN)
                    .eq(CouponOrder::getId, order.getId())
                    .update();
            //@create by FanJq 2024/12/20 14:52 更新背包优惠券状态
            userCouponService.lambdaUpdate()
                    .set(UserCoupon::getStatus, _Whole.ZERO)
                    .eq(UserCoupon::getOrderNo, orderNo)
                    .eq(UserCoupon::getUserId, userId)
                    .update();
        }
        return orderNo;
    }

    /**
     * @Description
     * 获取订单详情
     * @date 2024/12/20 15:52
     * @author FanJq
     * @param userId
     * @param orderNo
     * @return {@link CouponOrderDetailsResponse}
    */
    @Override
    public CouponOrderDetailsResponse getDetails(String userId, String orderNo) {
        CouponOrderDetailsResponse response = super.baseMapper.getDetails(userId, orderNo);
        response.setQuota(response.getQuotaBD().stripTrailingZeros().toPlainString());
        if (response.getType() == _Whole.ONE) {
            response.setQuota(response.getQuotaBD().multiply(new BigDecimal("10")).stripTrailingZeros().toPlainString());
        }
        if (response.getStatus().intValue() == _Whole.ONE) {
            UserCoupon userCoupon = userCouponService.getByOrderNo(userId, response.getOrderNo());
            if (ObjectUtil.isNotNull(userCoupon)) {
                response.setReceiveTime(DateUtils.time_sdf.get().format(userCoupon.getReceiveTime()));
                response.setExpireTime(DateUtils.time_sdf.get().format(userCoupon.getExpireTime()));
            }
            //@create by FanJq 2024/12/20 15:59 生成核销码
            response.setVerifyQrCode(buildVerifyQrCode(response.getVerifyCode()));
        }
        if (response.getStatus().intValue() == _Whole.SEVEN || response.getStatus().intValue() == _Whole.EIGHT) {
            //@create by FanJq 2024/12/19 17:05 组建退款数据
            RefundCouponOrder refundOrder = refundCouponOrderService.getByOrderNo(orderNo);
            if (ObjectUtil.isNotNull(refundOrder)) {
                response.setRefundOrderNo(refundOrder.getRefundOrderNo());
                response.setRefundPrice(refundOrder.getRefundPrice());
                response.setRefundTimeStr(DateUtils.time_sdf.get().format(refundOrder.getCreateTime()));
                response.setReason(refundOrder.getReason());
            }
        }
        return response;
    }

    /**
     * @Description
     * 立即使用
     * @date 2024/12/23 17:57
     * @author FanJq
     * @param userId
     * @param couponId
     * @return {@link CouponOrderDetailsResponse}
     */
    @Override
    public CouponOrderDetailsResponse getUseIndex(String userId, String couponId) {
        UserCoupon coupon = userCouponService.getUserUsableCoupon(userId, couponId);
        if (ObjectUtil.isNull(coupon) || StrUtil.isBlank(coupon.getOrderNo()))
            throw new DataHandleException("优惠券状态异常");
        CouponOrderDetailsResponse response = this.getDetails(userId, coupon.getOrderNo());
        return response;
    }


    /**
     * @Description
     * 订单执行退款逻辑
     * @date 2024/12/20 15:33
     * @author FanJq
     * @param refundCouponOrder
     * @param status
     * @return
    */
    @Override
    @Async("taskExecutor")
    public void refundLogic(RefundCouponOrder refundCouponOrder, int status) {
        CouponOrder couponOrder = this.getByOrderNo(refundCouponOrder.getUserId(), refundCouponOrder.getOrderNo());
        if (couponOrder.getStatus().intValue() != _Whole.SEVEN) return;
        UserCoupon userCoupon = userCouponService.getByOrderNo(couponOrder.getUserId(), couponOrder.getOrderNo());
        if (status == _Whole.ONE) { //@create by FanJq 2024/12/20 15:15 退款通过
            //@create by FanJq 2024/12/20 15:25 更新订单状态
            super.lambdaUpdate()
                    .set(CouponOrder::getStatus, _Whole.EIGHT)
                    .eq(CouponOrder::getOrderNo, couponOrder.getOrderNo())
                    .update();
            //@create by FanJq 2024/12/20 15:25 更新背包优惠券状态
            if (userCoupon.getStatus().intValue() != _Whole.ZERO) {
                userCouponService.lambdaUpdate()
                        .set(UserCoupon::getStatus, _Whole.ZERO)
                        .eq(UserCoupon::getId, userCoupon.getId())
                        .update();
            }
        } else if (status == _Whole.NINE) { //@create by FanJq 2024/12/20 15:30 退款驳回
            //@create by FanJq 2024/12/20 15:22 优惠券已过期
            if (userCoupon.getExpireTime().getTime() < new Date().getTime()) {
                //@create by FanJq 2024/12/20 15:25 更新订单状态
                super.lambdaUpdate()
                        .set(CouponOrder::getStatus, _Whole.FOUR)
                        .eq(CouponOrder::getOrderNo, couponOrder.getOrderNo())
                        .update();
                //@create by FanJq 2024/12/20 15:25 更新背包优惠券状态
                if (userCoupon.getStatus().intValue() != _Whole.ZERO) {
                    userCouponService.lambdaUpdate()
                            .set(UserCoupon::getStatus, _Whole.ZERO)
                            .eq(UserCoupon::getId, userCoupon.getId())
                            .update();
                }
            } else { //@create by FanJq 2024/12/20 15:25 优惠券未过期
                //@create by FanJq 2024/12/20 15:25 更新订单状态
                super.lambdaUpdate()
                        .set(CouponOrder::getStatus, _Whole.ONE)
                        .eq(CouponOrder::getOrderNo, couponOrder.getOrderNo())
                        .update();
                //@create by FanJq 2024/12/20 15:25 更新背包优惠券状态
                userCouponService.lambdaUpdate()
                        .set(UserCoupon::getStatus, _Whole.ONE)
                        .eq(UserCoupon::getId, userCoupon.getId())
                        .update();
            }
        }
    }

    /**
     * @Description
     * 管理后台列表
     * @date 2025/1/8 11:01
     * @author FanJq
     * @param orderNo
     * @param keywords
     * @param title
     * @param status
     * @param createTimeBegin
     * @param createTimeEnd
     * @return {@link List< CouponOrderAdmin>}
    */
    @Override
    public List<CouponOrderAdmin> getAdminList(String orderNo, String keywords, String title, Integer status, String createTimeBegin, String createTimeEnd) {
        if (StrUtil.isAllNotBlank(createTimeBegin, createTimeEnd))
            createTimeEnd = createTimeEnd + " 23:59:59";
        List<CouponOrderAdmin> resultList = super.baseMapper.getAdminList(orderNo, keywords, title, status, createTimeBegin, createTimeEnd);
        resultList.forEach(model -> {
            if (model.getType() == 1) {
                model.setQuotaStr(model.getQuota().stripTrailingZeros().toPlainString()+"折");
            } else if (model.getType() == 2){
                model.setQuotaStr("￥"+model.getQuota().stripTrailingZeros().toPlainString());
            }

        });
        return resultList;
    }

    /**
     * @Description
     * 订单统计
     * @date 2025/2/12 14:03
     * @author FanJq
     * @param
     * @return {@link Map< String, Object>}
    */
    @Override
    public Map<String, Object> getOrderStat() {
        Map<String, Object> result = this.baseMapper.getOrderStat();
        return result;
    }

    /**
     * @Description
     * 优惠券订单过期事件
     * @date 2025/2/19 19:01
     * @author FanJq
     * @param order
     * @return
     */
    @Override
    @Async("taskExecutor")
    public void expiredEvent(CouponOrder order) {
        super.lambdaUpdate()
                .set(CouponOrder::getStatus, _Whole.NINE)
                .eq(CouponOrder::getStatus, _Whole.ZERO)
                .eq(CouponOrder::getId, order.getId())
                .update();
    }

    /**
     * @Description
     * 计算订单金额
     * @date 2024/12/18 16:12
     * @author FanJq
     * @param userId
     * @param coupon
     * @return {@link CouponOrder}
    */
    public CouponOrder calculateOrder(String userId, Coupon coupon) {
        //@create by FanJq 2024/12/18 16:07 组建订单
        CouponOrder order = new CouponOrder();
        order.setOrderNo(UUIDGenerator.getOrderNoByTime(_Whole.couponOrderNoPrefix));
        order.setUserId(userId);
        order.setStoreId(coupon.getStoreId());
        order.setCouponId(coupon.getId());
        order.setTitle(coupon.getTitle());
        order.setScope(coupon.getScope());
        order.setType(coupon.getType());
        order.setQuota(coupon.getQuota());
        order.setBuyNum(_Whole.ONE);
        BigDecimal orderAmount = coupon.getPrice().multiply(new BigDecimal(order.getBuyNum())).setScale(2, RoundingMode.HALF_UP);
        order.setOrderAmount(orderAmount);
        order.setPayPrice(orderAmount);
        order.setPrice(coupon.getPrice());
        return order;
    }

    /**
     * @Description
     * 生成核销二维码
     * @date 2024/12/26 11:49
     * @author FanJq
     * @param verifyCode
     * @return {@link String}
    */
    private String buildVerifyQrCode(String verifyCode){
        Map<String, String> params = new HashMap<String, String>(){{
            put("a", "coupon");
            put("b", verifyCode);
            put("c", oConvertUtils.randomGen(3));
        }};
        String jsonString = JSONObject.toJSONString(params);
        String encrypt = AesEncryptUtil.encrypt(jsonString);
        return QrCodeUtil.generateAsBase64(encrypt, new QrConfig(), "png");
    }
}
